package com.dsteiner.widgets.client;

import java.util.Date;

import com.dsteiner.widgets.client.Widgets.IWidget;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.URL;
import com.google.gwt.http.client.RequestBuilder.Method;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventPreview;
import com.google.gwt.user.client.IncrementalCommand;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.WindowResizeListener;
import com.google.gwt.user.client.WindowScrollListener;
import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.google.gwt.user.client.Window.ScrollHandler;
import com.google.gwt.user.client.ui.Widget;

public class JsUtil implements IJsUtil {

	public static final String PRINT_URL = "print";
	private static IJsUtil instance;

	static {
		initJsHooks();
	}

	public boolean isIphoneUserAgent = isIphoneUserAgent();

	// public static boolean isIphoneUserAgent = true;

	private JsUtil() {
	}

	public static IJsUtil getInstance() {
		if (instance == null)
			instance = new JsUtil();
		return instance;
	}

	public native void setLocation(String url) /*-{
	  $wnd.location = url;
	}-*/;

	public void removeCookie(String name) {
		Cookies.removeCookie(name);
	}
	public void addCookie(String name, String value) {
		Date expires = new Date();
		expires.setTime(new Date().getTime() + (14 * DateUtilImpl.DAY_IN_MS));
		// sets it for approx 14 days.
		String domainUrl = getDomainUrlShort();
		Cookies.setCookie(name, value, expires, null, "/", false);
	}

	public String getDomainUrlShort() {
		String domainUrl = getDomainUrl();
		domainUrl = domainUrl.substring("http://".length());
		return domainUrl;
	}

	public String getDomainUrl() {
		String moduleBaseURL = GWT.getModuleBaseURL();
//		if (moduleBaseURL.indexOf("localhost") != -1 || moduleBaseURL.indexOf("10.0.2.1") != -1)
//			return "http://beta.homeprodigy.com";
//		else {
			String host = moduleBaseURL.substring(0, moduleBaseURL.indexOf("/",
					"http://".length()));
			return host;
//		}

	}

	public String getInfoFromDiv(String divId) {
		Element element = DOM.getElementById(divId);
		return element != null ? DOM.getInnerText(element) : null;
	}

	public String getCookie(String name) {
		// if("agent_id".equals(name))
		// return "0128047";
		// else if("office_id".equals(name))
		// return "GMAC01";
		return Cookies.getCookie(name);
	}

	public void showAlert(String text) {
		Window.alert(text);
	}

	public void addWindowResizeListener(
			WindowResizeListener windowResizeListener) {
		Window.addWindowResizeListener(windowResizeListener);
	}
	public void addWindowResizeHandler(ResizeHandler handler) {
		Window.addResizeHandler(handler);
	}
	public void addWindowScrollHandler(ScrollHandler handler) {
		Window.addWindowScrollHandler(handler);
	}

	public int getClientHeight() {
		return Window.getClientHeight();
	}

	public int getClientWidth() {
		return Window.getClientWidth();
	}

	/**
	 * G[et]U[rl]P[rop] Similar to request.getProperty(name), but works only on
	 * URL, because it's client-side
	 * 
	 * @param name
	 * @return
	 */
	public String gup(String name) {
		return gup(getHref(), name);
	}

	public native String gup(String url, String name) /*-{
	    var rgx=new RegExp("[\\?&]"+name+"=([^&#]*)");
	    var s=rgx.exec(url);
	    return s==null?"":s[1];
	  }-*/;

	public String format(double number, String pattern) {
		return NumberFormat.getFormat(pattern).format(number);
	}

	public void openWindow(String url, String name, String features) {
		Window.open(url, name, features);
	}

	public boolean isNotTemplateSite() {
		String domain = getDomainUrl();
		boolean isNotTemplateSite = domain.indexOf("beta.homeprodigy.com") != -1
				|| domain.indexOf("www.homeprodigy.com") != -1
				|| domain.indexOf("weekly.homeprodigy.com") != -1;
		return isNotTemplateSite;
		// TODO just for test reason
		// return false;
	}

	public boolean isWwwSite() {
		String domain = getDomainUrl();
		boolean isWwwSite = domain.indexOf("www.homeprodigy.com") != -1;
		return isWwwSite;
	}

	public void cancelCurrentEvent() {
		DOM.eventCancelBubble(DOM.eventGetCurrentEvent(), true);
	}

	public void setStyleAttribute(IWidget widget, String name, String value) {
		DOM.setStyleAttribute(((Widget) widget).getElement(), name, value);
	}

	public native void open(String url, String name, String features, int top,
			int left) /*-{
	    mywindow = $wnd.open(url, name, features);
	    mywindow.moveTo(top,left);
	}-*/;

	public native String getHref() /*-{
	    return $wnd.location.href;
	}-*/;

	public native boolean isIphoneUserAgent() /*-{
		var agent=navigator.userAgent.toLowerCase();
		var is_iphone = (agent.indexOf('iphone')!=-1);
		return is_iphone == true;
	}-*/;

	public native boolean isIphoneUserAgent(String userAgent) /*-{
		var agent=userAgent.toLowerCase();
		var is_iphone = (agent.indexOf('iphone')!=-1);
		return is_iphone == true;
	}-*/;

	public native String md5(String url) /*-{
		var server = parseInt($wnd.hex_md5(url).substring(0,1),16) % 4;
		url = url.replace("static.homeprodigy.com","static"+server+".homeprodigy.com");
		return url;
	}-*/;

	private native static void initJsHooks() /*-{
	var hexcase = 0; 
	var b64pad  = "";
	var chrsz   = 8; 
	
	$wnd.safe_add = function (x, y)
	{
	  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
	  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
	  return (msw << 16) | (lsw & 0xFFFF);
	}
	
	$wnd.bit_rol = function (num, cnt)
	{
	  return (num << cnt) | (num >>> (32 - cnt));
	}
	
	$wnd.str2binl = function (str)
	{
	  var bin = Array();
	  var mask = (1 << chrsz) - 1;
	  for(var i = 0; i < str.length * chrsz; i += chrsz)
	    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
	  return bin;
	}
	
	$wnd.core_md5 = function (x, len)
	{
	  x[len >> 5] |= 0x80 << ((len) % 32);
	  x[(((len + 64) >>> 9) << 4) + 14] = len;
	
	  var a =  1732584193;
	  var b = -271733879;
	  var c = -1732584194;
	  var d =  271733878;
	
	  for(var i = 0; i < x.length; i += 16)
	  {
	    var olda = a;
	    var oldb = b;
	    var oldc = c;
	    var oldd = d;
	
	    a = $wnd.md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
	    d = $wnd.md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
	    c = $wnd.md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
	    b = $wnd.md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
	    a = $wnd.md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
	    d = $wnd.md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
	    c = $wnd.md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
	    b = $wnd.md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
	    a = $wnd.md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
	    d = $wnd.md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
	    c = $wnd.md5_ff(c, d, a, b, x[i+10], 17, -42063);
	    b = $wnd.md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
	    a = $wnd.md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
	    d = $wnd.md5_ff(d, a, b, c, x[i+13], 12, -40341101);
	    c = $wnd.md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
	    b = $wnd.md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
	
	    a = $wnd.md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
	    d = $wnd.md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
	    c = $wnd.md5_gg(c, d, a, b, x[i+11], 14,  643717713);
	    b = $wnd.md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
	    a = $wnd.md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
	    d = $wnd.md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
	    c = $wnd.md5_gg(c, d, a, b, x[i+15], 14, -660478335);
	    b = $wnd.md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
	    a = $wnd.md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
	    d = $wnd.md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
	    c = $wnd.md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
	    b = $wnd.md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
	    a = $wnd.md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
	    d = $wnd.md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
	    c = $wnd.md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
	    b = $wnd.md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
	
	    a = $wnd.md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
	    d = $wnd.md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
	    c = $wnd.md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
	    b = $wnd.md5_hh(b, c, d, a, x[i+14], 23, -35309556);
	    a = $wnd.md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
	    d = $wnd.md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
	    c = $wnd.md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
	    b = $wnd.md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
	    a = $wnd.md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
	    d = $wnd.md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
	    c = $wnd.md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
	    b = $wnd.md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
	    a = $wnd.md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
	    d = $wnd.md5_hh(d, a, b, c, x[i+12], 11, -421815835);
	    c = $wnd.md5_hh(c, d, a, b, x[i+15], 16,  530742520);
	    b = $wnd.md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
	
	    a = $wnd.md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
	    d = $wnd.md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
	    c = $wnd.md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
	    b = $wnd.md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
	    a = $wnd.md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
	    d = $wnd.md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
	    c = $wnd.md5_ii(c, d, a, b, x[i+10], 15, -1051523);
	    b = $wnd.md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
	    a = $wnd.md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
	    d = $wnd.md5_ii(d, a, b, c, x[i+15], 10, -30611744);
	    c = $wnd.md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
	    b = $wnd.md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
	    a = $wnd.md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
	    d = $wnd.md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
	    c = $wnd.md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
	    b = $wnd.md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
	
	    a = $wnd.safe_add(a, olda);
	    b = $wnd.safe_add(b, oldb);
	    c = $wnd.safe_add(c, oldc);
	    d = $wnd.safe_add(d, oldd);
	  }
	  return Array(a, b, c, d);
	
	}
	
	$wnd.md5_cmn = function (q, a, b, x, s, t)
	{
	  return $wnd.safe_add($wnd.bit_rol($wnd.safe_add($wnd.safe_add(a, q), $wnd.safe_add(x, t)), s),b);
	}
	$wnd.md5_ff = function (a, b, c, d, x, s, t)
	{
	  return $wnd.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
	}
	$wnd.md5_gg = function (a, b, c, d, x, s, t)
	{
	  return $wnd.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
	}
	$wnd.md5_hh = function (a, b, c, d, x, s, t)
	{
	  return $wnd.md5_cmn(b ^ c ^ d, a, b, x, s, t);
	}
	$wnd.md5_ii = function (a, b, c, d, x, s, t)
	{
	  return $wnd.md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
	}
	
	$wnd.binl2hex = function (binarray)
	{
	  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
	  var str = "";
	  for(var i = 0; i < binarray.length * 4; i++)
	  {
	    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
	           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
	  }
	  return str;
	}
	
	$wnd.hex_md5 = function (s){ return $wnd.binl2hex($wnd.core_md5($wnd.str2binl(s), s.length * chrsz));}
	
	}-*/;

	public void setPrintableImageUrl(IWidget widget, String url) {
		DOM.setElementAttribute(((Widget) widget).getElement(), PRINT_URL, url);
	}

	public boolean isPropertyDetailsPage() {
		String mainPage = gup("main_page");
		return "home_search_details".equals(mainPage);
	}

	public int getScrollLeft() {
		return Window.getScrollLeft();
	}

	public int getScrollTop() {
		return Window.getScrollTop();
	}

	public boolean isGalleryPage() {
		String mainPage = gup("main_page");
		return "gallery".equals(mainPage);
	}

	public boolean isMapPage() {
		String mainPage = gup("main_page");
		return "map".equals(mainPage);
	}

	public boolean isAccountValidationPage() {
		String mainPage = gup("main_page");
		return "account_verification".equals(mainPage);
	}
	
	public boolean isLoginPage() {
		String mainPage = gup("main_page");
		return "login".equals(mainPage);
	}
	
	public void addWindowScrollListener(
			WindowScrollListener windowScrollListener) {
		Window.addWindowScrollListener(windowScrollListener);
	}

	public void trackEvent(final String category, final String action){
		trackEvent(category, action, null, null);
	}
	
	public void trackEvent(final String category, final String action, String optionalLabel){
		trackEvent(category, action, optionalLabel, null);
	}
			
	public void trackEvent(final String category, final String action, final String optionalLabel, 
			final String optionalValue) {
		addCommand(new Command() {
			public void execute() {
				String webTrackingKey = getInfoFromDiv("WEB_TRACKING_KEY");
				if (webTrackingKey == null) {
					System.err
					.println("no web tracking key found in hidden div WEB_TRACKING_KEY");
					return;
				}
				trackEvent(category, action, optionalLabel, optionalValue, webTrackingKey);
			}
		});
	}

	private native void trackEvent(String category, String action, String optional_label, String optional_value, 
			String accountId)/*-{
			var pageTracker = $wnd._gat._getTracker(accountId);
			pageTracker._initData(); 
			pageTracker._trackEvent(category, action, optional_label, optional_value);
		}-*/;
	
	public void trackUrchinHit(final String pageName) {
		addCommand(new Command() {
			public void execute() {
				String webTrackingKey = getInfoFromDiv("WEB_TRACKING_KEY");
				if (webTrackingKey == null) {
					System.err
							.println("no web tracking key found in hidden div WEB_TRACKING_KEY");
					return;
				}
				trackUrchinHit(pageName, webTrackingKey);
			}
		});
	}

	private native void trackUrchinHit(String pageName, String accountId)/*-{
			var pageTracker = $wnd._gat._getTracker(accountId);
			pageTracker._trackPageview(pageName);
		}-*/;

	public void trackGAVar(final String varName) {
		addCommand(new Command() {
			public void execute() {
				String webTrackingKey = getInfoFromDiv("WEB_TRACKING_KEY");
				if (webTrackingKey == null) {
					System.err
					.println("no web tracking key found in hidden div WEB_TRACKING_KEY");
					return;
				}
				trackGAVar(varName, webTrackingKey);
			}
		});
	}

	private native void trackGAVar(String varName, String accountId)/*-{
			var pageTracker = $wnd._gat._getTracker(accountId);
			pageTracker._setVar(varName);
		}-*/;
	
	public void addEventPreview(EventPreview eventListener) {
		DOM.addEventPreview(eventListener);
	}
	
	public void addEventPreviewHander(NativePreviewHandler handler) {
		Event.addNativePreviewHandler(handler);
	}

	public void removeEventPreview(EventPreview eventListener) {
		DOM.removeEventPreview(eventListener);
	}

	public void addCommand(Command command) {
		DeferredCommand.addCommand(command);
	}

	public void addCommand(IncrementalCommand incrementalCommand) {
		DeferredCommand.addCommand(incrementalCommand);
	}

	public String getUserAgentId() {
		String userEmail = getCookie(COOKIE_USER_AGENT_ID);
		return userEmail;
	}

	public String getUserEmail() {
		String userEmail = getCookie(COOKIE_USER_EMAIL);
		return userEmail;
	}

	public Integer getUserId() {
		String id = getCookie(COOKIE_USER_ID);
		return id != null && !id.equals("") ? new Integer(id) : null;
	}

	public String getUserName() {
		String cookieUserName = getCookie(COOKIE_USER_NAME);
		String userName = cookieUserName != null && !"".equals(cookieUserName) ? URL
				.decodeComponent(cookieUserName)
				: cookieUserName;
		return userName;
	}

	public String getUserType() {
		String cookieUserType = getCookie(COOKIE_USER_TYPE);
		return cookieUserType;
	}

	public String getUserTypeVerified() {
		String cookieUserTypeVerified = getCookie(COOKIE_USER_TYPE_VERIFIED);
		return cookieUserTypeVerified;
	}

	public String getUserCity() {
		return getInfoFromDiv(USER_CITY);
	}

	public Integer getUserCustId() {
		String tempId = getInfoFromDiv(USER_CUST_ID);
		return tempId != null ? new Integer(tempId) : null;
	}

	public String getUserIp() {
		return getInfoFromDiv(USER_IP);
	}

	public Float getUserLat() {
		String lat = getInfoFromDiv(USER_LAT);
		return lat != null ? new Float(lat) : null;
	}

	public Float getUserLng() {
		String lng = getInfoFromDiv(USER_LNG);
		return lng != null ? new Float(lng) : null;
	}

	public String getUserState() {
		return getInfoFromDiv(USER_STATE);
	}

	public String getUserTempId() {
		String tempId = getInfoFromDiv(USER_TEMP_ID);
		return tempId;
	}

	public String getUserUri() {
		return getInfoFromDiv(USER_URI);
	}

	public boolean isUserTypeVerified(String userVerificated) {
		return "true".equalsIgnoreCase(userVerificated);
	}

	public Request sendRequest(String url, int method,
			RequestCallback requestCallback) {
		Method methodRequest = method == GET ? RequestBuilder.GET
				: RequestBuilder.POST;
		RequestBuilder builder = new RequestBuilder(methodRequest, url);
		try {
			return builder.sendRequest(null, requestCallback);
		} catch (RequestException e) {
			e.printStackTrace();
		}
		return null;
	}

	public String encodeComponent(String decodedURLComponent) {
		return URL.encodeComponent(decodedURLComponent);
	}

	public native void sendRequest(int requestId, String url, ResponseHandler handler) /*-{
	    var callback = "callback" + requestId;
	    
	    var script = document.createElement("script");
	    script.setAttribute("src", url+callback);
	    script.setAttribute("type", "text/javascript");

	    window[callback] = function(text) {
	      handler.@com.dsteiner.widgets.client.ResponseHandler::handleResponse(Ljava/lang/String;)(text);
	      window[callback + "done"] = true;
	    }
	    
	    // JSON download has 1-second timeout
	    setTimeout(function() {
	      if (!window[callback + "done"]) {
	        handler.@com.dsteiner.widgets.client.ResponseHandler::handleResponse(Ljava/lang/String;)(null);
	      } 

	      // cleanup
	      document.body.removeChild(script);
	      delete window[callback];
	      delete window[callback + "done"];
	    }, 5000);
	    
	    document.body.appendChild(script);
	}-*/;

	public native boolean isIe6()/*-{
	var agt=navigator.userAgent.toLowerCase();
	var is_major = parseInt(navigator.appVersion);
	var is_ie     = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
    return (is_ie && (is_major == 4) && (agt.indexOf("msie 6.")!=-1));
	}-*/;
//	public boolean isIe6(){
//		return true;
//	}
	
}
